package test;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.jar.JarOutputStream;

import javax.enterprise.deploy.shared.StateType;
import javax.enterprise.deploy.spi.DeploymentManager;
import javax.enterprise.deploy.spi.Target;
import javax.enterprise.deploy.spi.TargetModuleID;
import javax.enterprise.deploy.spi.status.DeploymentStatus;
import javax.enterprise.deploy.spi.status.ProgressObject;

import org.jboss.as.ee.deployment.spi.DeploymentMetaData;
import org.jboss.as.ee.deployment.spi.JarUtils;

//import org.jboss.deployment.spi.DeploymentMetaData;
//import org.jboss.deployment.spi.JarUtils;

/**JSR88 Deployer for JBoss 7: deploys a file to a JBoss server.
 * 
 * @author Wolfgang Knauf
 * 
 * @version 2011-01-12  First version (created from AS4 deployer file)
 */
public class JSR88Deployer
{
  /**
   * Main method. Waits until an app is deployed.
   * 
   * @param args Command line. <br>
   *          first argument: the url of the deployed file. <br> 
   *          second argument: server host ("localhost") <br>
   *          third argument: port (default: 1099) <br>
   */
  public static void main(String[] args)
  {
    try
    {
      if (args.length != 3)
      {
        throw new IllegalArgumentException("Three arguments must be specified instead of " + args.length + ": url serverAddress jndiPort");
      }
      //Get file:
      String strUrl = args[0];
      File fileDeploy = new File (strUrl);
      System.out.println("Deploying file '" + strUrl + "' to host '" + args[1] + ":" + args[2] + "'");

    
      //Get a Deployment manager:
      DeploymentManager dm = JSR88DeployerUtil.getDeploymentManager(args[1], args[2]);
      if (dm == null)
      {
        return;
      }
      
      //Deploy file:
      ProgressObject po = JSR88Deployer.jsr88Deployment(fileDeploy.getParent(), fileDeploy.getName(), dm);
      
      //Output Module IDs, if successful:
      if (po != null)
      {
        System.out.println ("Deployed file. ModuleIDs: ");
        TargetModuleID[] modules = po.getResultTargetModuleIDs();
        for (int intIndexModule = 0; intIndexModule < modules.length; intIndexModule++)
        {
          System.out.println ("\t" + modules[intIndexModule].toString());
        }
      }
      
    }
    catch (Exception ex)
    {
      System.out.println ("Exception caught!");
      ex.printStackTrace();
    }
  }
  
  /**Deploy a file to a deployment manager.
   * 
   * @param strPath Path to the file
   * @param module  The file name
   * @param manager DeploymentManager
   * @return A ProgressObject, or NULL is deployment failed because of errors in the file.
   * @throws Exception
   */
  private static ProgressObject jsr88Deployment(String strPath, String module, DeploymentManager manager) throws Exception
  {
    // Get the distribution targets
    Target[] targets = manager.getTargets();
  
    File deploymentPlan = createDeploymentPlan(module);
    
    //We need the file with absolute path:
    File moduleArchive = new File(strPath, module);
    
    // Deploy the file:
    ProgressObject progress = manager.distribute(targets, moduleArchive, deploymentPlan);
    DeploymentStatus status = progress.getDeploymentStatus();
    if (status.getState() == StateType.FAILED)
    {
      //Deployment may fail, if e.g. "ejb-jar.xml" is broken!
      //Don't report full message, as it may contain a lot of stack traces.
      //System.out.println ("Deployment failed: " + status.getMessage());
      System.out.println ("Deployment failed, see server log.");
      return null;
    }
    JSR88DeployerUtil.waitForCompletion(status);
  
    //Start Module:
    TargetModuleID[] moduleIDs = progress.getResultTargetModuleIDs();
    progress = manager.start(moduleIDs);
    status = progress.getDeploymentStatus();
    JSR88DeployerUtil.waitForCompletion(status);
  
    if (status.getState() == StateType.FAILED)
    {
      //Start may fail, if e.g. "ejb-jar.xml" is broken!
      //Don't report full message, as it may contain a lot of stack traces.
      System.err.println ("Start of application failed, see server log.");
      return null;
    }
    return progress;
  }
  
  /**Creates a deployment plan (zip file) in the temp dir.
   * 
   * @param deploymentFile This is the file to be deployed (full path)
   * @return The file which contains the deployment plan
   * @throws Exception All exceptions...
   */
  private static File createDeploymentPlan(String deploymentFile) throws Exception
  {
    // Create temp file for deployment plan
    File deploymentPlan = File.createTempFile("deploymentplan", ".zip");
    deploymentPlan.deleteOnExit();

    JarOutputStream jos = new JarOutputStream(new FileOutputStream(deploymentPlan));

    // Setup deployment plan meta data with proprietary descriptor
    DeploymentMetaData metaData = new DeploymentMetaData(deploymentFile);

    // Add the meta data to the deployment plan
    String metaStr = metaData.toXMLString();

    JarUtils.addJarEntry(jos, DeploymentMetaData.ENTRY_NAME, new ByteArrayInputStream(metaStr.getBytes()));
    jos.flush();
    jos.close();

    return deploymentPlan;
  }
}